package tianrun.ziguan.api.calculate.config.service.business.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import tianrun.ziguan.api.calculate.config.constant.StringPools;
import tianrun.ziguan.api.calculate.config.dto.request.*;
import tianrun.ziguan.api.calculate.config.dto.response.*;
import tianrun.ziguan.api.calculate.config.service.asset.group.ITAssetGroupService;
import tianrun.ziguan.api.calculate.config.service.asset.instance.ITAssetEdgeInputInstanceService;
import tianrun.ziguan.api.calculate.config.service.asset.instance.ITAssetStaticPropertiesInstanceService;
import tianrun.ziguan.api.calculate.config.service.asset.module.ITAssetStaticPropertiesModuleService;
import tianrun.ziguan.api.calculate.config.service.business.RefreshCacheService;
import tianrun.ziguan.api.calculate.config.constant.RedisKeyConstants;
import tianrun.ziguan.api.calculate.config.entity.*;
import tianrun.ziguan.api.calculate.config.service.asset.module.ITAssetUsageAnalysisModuleService;
import tianrun.ziguan.api.calculate.config.service.asset.callabel.ITAssetCalLabelConfigService;
import tianrun.ziguan.api.calculate.config.service.asset.experssion.ITAssetExpressionService;
import tianrun.ziguan.api.calculate.config.service.asset.instance.ITAssetIndicatorsInstanceService;
import tianrun.ziguan.api.calculate.config.service.cal.asset.ITCalAssetService;
import tianrun.ziguan.api.calculate.config.service.redis.IRedisService;
import tianrun.ziguan.api.calculate.config.service.redis.RedisMessagePublisher;
import tianrun.ziguan.api.calculate.config.utils.CollectionUtil;
import tianrun.ziguan.api.calculate.config.utils.StringUtil;
import tianrun.ziguan.api.common.exception.RedisConnectException;
import tianrun.ziguan.api.common.util.ListUtil;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author zhaoqi
 */
@Service
public class RefreshCacheServiceImpl implements RefreshCacheService {

    private final IRedisService redisService;
    private final ITCalAssetService calAssetService;
    private final ITAssetGroupService assetGroupService;
    private final ITAssetCalLabelConfigService assetCalLabelConfigService;
    private final ITAssetIndicatorsInstanceService assetIndicatorsInstanceService;
    private final ITAssetUsageAnalysisModuleService assetUsageAnalysisModuleService;
    private final ITAssetExpressionService assetExpressionService;
    private final ITAssetEdgeInputInstanceService assetEdgeInputInstanceService;
    private final ITAssetStaticPropertiesInstanceService staticPropertiesInstanceService;
    private final RedisMessagePublisher redisMessagePublisher;
    private static final Logger log = LoggerFactory.getLogger(RefreshCacheService.class);
    private static final Map<String, Lock> LOCK_MAP = new ConcurrentHashMap<>();
    @Value("${spring.redis.databaseByData}")
    private Integer databaseByData;
    @Value("${spring.redis.flushCacheChannelName}")
    private String flushCacheChannelName;

    public RefreshCacheServiceImpl(IRedisService redisService, ITCalAssetService calAssetService, ITAssetGroupService assetGroupService, ITAssetCalLabelConfigService assetCalLabelConfigService, ITAssetIndicatorsInstanceService assetIndicatorsInstanceService, ITAssetUsageAnalysisModuleService assetUsageAnalysisModuleService, ITAssetExpressionService assetExpressionService, ITAssetEdgeInputInstanceService assetEdgeInputInstanceService, ITAssetStaticPropertiesInstanceService staticPropertiesInstanceService, RedisMessagePublisher redisMessagePublisher) {
        this.redisService = redisService;
        this.calAssetService = calAssetService;
        this.assetGroupService = assetGroupService;
        this.assetCalLabelConfigService = assetCalLabelConfigService;
        this.assetIndicatorsInstanceService = assetIndicatorsInstanceService;
        this.assetUsageAnalysisModuleService = assetUsageAnalysisModuleService;
        this.assetExpressionService = assetExpressionService;
        this.assetEdgeInputInstanceService = assetEdgeInputInstanceService;
        this.staticPropertiesInstanceService = staticPropertiesInstanceService;
        this.redisMessagePublisher = redisMessagePublisher;
    }

    @Override
    public void refreshAssetGroup(BusinessParam param) {
        String deptNum = param.getDeptNum();
        Assert.isTrue(StringUtil.isNotEmpty(param.getDeptNum()), "请传入资产组名称");
        List<TCalAsset> calAssets = calAssetService.queryAssetList(deptNum);
        if (CollectionUtil.isEmpty(calAssets)) {
            return;
        }
        Optional<TCalAsset> first = calAssets.stream().filter(it -> StringUtil.isBlank(it.getParentAssetNum())).findFirst();
        if (!first.isPresent()) {
            return;
        }
        Map<String, String> parentStringMap = Maps.newHashMap();
        String assetNum = first.get().getAssetNum();
        Map<String, List<String>> parentMap = calAssets.stream().filter(it -> StringUtil.isNotBlank(it.getParentAssetNum())).collect(Collectors.groupingBy(TCalAsset::getParentAssetNum, Collectors.mapping(TCalAsset::getAssetNum, Collectors.toList())));
        List<String> list = parentMap.getOrDefault(assetNum, Lists.newArrayList());
        list.removeIf(StringUtil::isEmpty);
        parentStringMap.put(assetNum, JSONObject.toJSONString(list));
        parentStringMap.putAll(conversionJson(parentMap));
        String hKey = String.format(RedisKeyConstants.ASSET_CHILD_PREFIX, deptNum, deptNum);
        delOldHashKey(hKey, parentStringMap.keySet());
        redisService.pipelineHSet(hKey, parentStringMap);
    }

    private <V> Map<String, String> conversionJson(Map<String, V> parentMap) {
        Map<String, String> resultMap = Maps.newHashMap();
        for (Map.Entry<String, V> listEntry : parentMap.entrySet()) {
            resultMap.put(listEntry.getKey(), JSONObject.toJSONString(listEntry.getValue()));
        }
        return resultMap;
    }

    @Override
    public void refreshAssetLabel(BusinessParam param) {
        Assert.isTrue(StringUtil.isNotEmpty(param.getTableName()), "请传入tableName");
        HashMap<String, Map<String, Set<AssetLabelRespDetail>>> redisKeyMap = new HashMap<>();
        List<TCalAsset> calAssets = getCalAssets(param);
        if (calAssets == null) return;
        Set<Long> ids = calAssets.stream().map(TCalAsset::getId).collect(Collectors.toSet());
        Map<String, List<String>> parentMap = calAssets.stream().filter(it -> StringUtil.isNotBlank(it.getParentAssetNum())).collect(Collectors.groupingBy(TCalAsset::getParentAssetNum, Collectors.mapping(TCalAsset::getAssetNum, Collectors.toList())));
        List<TAssetCalLabelConfigVO> calLabelResps = assetCalLabelConfigService.queryLabelListByCalAssetIds(ids, param.getTableName());
        if (CollectionUtil.isEmpty(calLabelResps)) {
            return;
        }
        //设备编码分组处理
        Map<String, List<TAssetCalLabelConfigVO>> listMap = calLabelResps.stream().collect(Collectors.groupingBy(TAssetCalLabelConfigVO::getAssetNum));
        for (Map.Entry<String, List<TAssetCalLabelConfigVO>> listEntry : listMap.entrySet()) {
            String assetNum = listEntry.getKey();
            List<TAssetCalLabelConfigVO> labelResps = listEntry.getValue();
            //点位分组处理
            labelResps.stream().filter(c -> Objects.nonNull(c.getLabel())).collect(Collectors.groupingBy(TAssetCalLabelConfigVO::getLabel))
                    .forEach((label, it) -> {
                        it.forEach(item -> {
                            AssetLabelRespDetail.parse(item, parentMap).forEach((assetNumber, assetLabelRespDetails) -> {
                                redisKeyMap.computeIfAbsent(String.format(RedisKeyConstants.ASSET_LABEL_PREFIX, param.getDeptNum(), assetNumber), key -> Maps.newHashMap())
                                        .computeIfAbsent(label, key -> Sets.newHashSet()).addAll(assetLabelRespDetails);
                            });
                        });
                    });
        }
        redisKeyMap.forEach((key, respListMap) -> {
            delOldHashKey(key, respListMap.keySet());
            redisService.pipelineHSet(key, conversionJson(respListMap));
        });
    }

    private List<TCalAsset> getCalAssets(BusinessParam param) {
        /*if (StringUtil.isNotEmpty(param.getAssetNum())){
            TCalAsset one = calAssetService.getOne(Wrappers.<TCalAsset>lambdaQuery().eq(TCalAsset::getAssetNum, param.getAssetNum()).last("limit 1"));
            if (null==one)return Lists.newArrayList();
            return Lists.newArrayList(one);
        }*/
        String deptNum = param.getDeptNum();
        return calAssetService.queryAssetList(deptNum);
    }

    @Override
    public void refreshAssetCallabel(BusinessParam param) {
        Assert.isTrue(StringUtil.isNotEmpty(param.getTableName()), "请传入tableName");
        List<TCalAsset> calAssets = getCalAssets(param);
        if (CollectionUtil.isEmpty(calAssets)) {
            return;
        }
        List<Long> ids = calAssets.stream().map(TCalAsset::getId).collect(Collectors.toList());
        List<TAssetCalLabelConfigVO> calLabelResps = assetCalLabelConfigService.queryLabelListByCalAssetIds(ids, param.getTableName());
        if (CollectionUtil.isEmpty(calLabelResps)) {
            return;
        }
        //设备编码分组处理
        Map<String, List<TAssetCalLabelConfigVO>> listMap = calLabelResps.stream().collect(Collectors.groupingBy(TAssetCalLabelConfigVO::getAssetNum));
        for (Map.Entry<String, List<TAssetCalLabelConfigVO>> listEntry : listMap.entrySet()) {
            String assetNum = listEntry.getKey();
            List<TAssetCalLabelConfigVO> labelResps = listEntry.getValue();
            //点位分组处理
            Map<String, AssetCalLabelDetail> labelDetailMap = labelResps.stream().collect(Collectors.groupingBy(TAssetCalLabelConfigVO::getCalLabel))
                    .entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, it -> AssetCalLabelDetail.parse(assetNum, it)));
            String hKey = String.format(RedisKeyConstants.ASSET_CALLABEL_PREFIX, param.getDeptNum(), assetNum);
            delOldHashKey(hKey, labelDetailMap.keySet());
            redisService.pipelineHSet(hKey, conversionJson(labelDetailMap));
        }
    }

    @Override
    public void refreshAssetInstanceData(BusinessParam param) {
        List<TCalAsset> calAssets = getCalAssets(param);
        if (CollectionUtil.isEmpty(calAssets)) {
            return;
        }
        List<Long> ids = calAssets.stream().map(TCalAsset::getId).collect(Collectors.toList());
        List<AssetIndicatorsInstanceVO> indicatorsInstances = assetIndicatorsInstanceService.queryInstanceList(ids, "data");
        if (CollectionUtil.isEmpty(indicatorsInstances)) {
            return;
        }
        Map<String, List<AssetIndicatorsInstanceVO>> listMap = indicatorsInstances.stream().collect(Collectors.groupingBy(AssetIndicatorsInstanceVO::getAssetNum));
        for (Map.Entry<String, List<AssetIndicatorsInstanceVO>> stringListEntry : listMap.entrySet()) {
            String assetNum = stringListEntry.getKey();
            List<AssetIndicatorsInstanceVO> value = stringListEntry.getValue();
            Map<String, AssetIndicatorsInstanceVO> instanceMap = value.stream().collect(Collectors.toMap(AssetIndicatorsInstanceVO::getCalLabel, Function.identity(), (a, b) -> b));
            String hKey = String.format(RedisKeyConstants.ASSET_INDICATORS_INSTANCE_DATA_PREFIX, param.getDeptNum(), assetNum);
            delOldHashKey(hKey, instanceMap.keySet());
            redisService.pipelineHSet(hKey, conversionJson(instanceMap));
        }
    }

    @Override
    public void refreshAssetInstanceTime(BusinessParam param) {
        List<TCalAsset> calAssets = getCalAssets(param);
        if (CollectionUtil.isEmpty(calAssets)) {
            return;
        }
        List<Long> ids = calAssets.stream().map(TCalAsset::getId).collect(Collectors.toList());
        List<AssetIndicatorsInstanceVO> indicatorsInstances = assetIndicatorsInstanceService.queryInstanceList(ids, "time");
        if (CollectionUtil.isEmpty(indicatorsInstances)) {
            return;
        }
        Map<String, List<AssetIndicatorsInstanceVO>> listMap = indicatorsInstances.stream().collect(Collectors.groupingBy(AssetIndicatorsInstanceVO::getAssetNum));
        for (Map.Entry<String, List<AssetIndicatorsInstanceVO>> stringListEntry : listMap.entrySet()) {
            String assetNum = stringListEntry.getKey();
            List<AssetIndicatorsInstanceVO> value = stringListEntry.getValue();
            Map<String, AssetIndicatorsInstanceVO> instanceMap = value.stream().collect(Collectors.toMap(AssetIndicatorsInstanceVO::getCalLabel, Function.identity(), (a, b) -> b));
            String hKey = String.format(RedisKeyConstants.ASSET_INDICATORS_INSTANCE_TIME_PREFIX, param.getDeptNum(), assetNum);
            delOldHashKey(hKey, instanceMap.keySet());
            redisService.pipelineHSet(hKey, conversionJson(instanceMap));
        }
    }

    @Override
    public void refreshAssetAnalysis(BusinessParam param) {
        List<TCalAsset> calAssets = getCalAssets(param);
        if (CollectionUtil.isEmpty(calAssets)) {
            return;
        }
        List<Long> ids = calAssets.stream().map(TCalAsset::getId).collect(Collectors.toList());
        List<TAssetUsageAnalysisModuleVO> analysisModules = assetUsageAnalysisModuleService.listByCalAssetIds(ids).
                stream().filter(a -> a.getCalLabel() != null).
                collect(Collectors.toList());
        if (CollectionUtil.isEmpty(analysisModules)) {
            return;
        }
        Map<String, List<TAssetUsageAnalysisModuleVO>> listMap = analysisModules.stream().collect(Collectors.groupingBy(TAssetUsageAnalysisModuleVO::getAssetNum));
        for (Map.Entry<String, List<TAssetUsageAnalysisModuleVO>> stringListEntry : listMap.entrySet()) {
            String assetNum = stringListEntry.getKey();
            List<TAssetUsageAnalysisModuleVO> value = stringListEntry.getValue();
            Map<String, TAssetUsageAnalysisModule> analysisModuleMap = value.stream().collect(Collectors.toMap(TAssetUsageAnalysisModule::getCalLabel, Function.identity(), (a, b) -> b));
            String hKey = String.format(RedisKeyConstants.ASSET_USAGE_ANALYSIS_PREFIX, param.getDeptNum(), assetNum);
            delOldHashKey(hKey, analysisModuleMap.keySet());
            redisService.pipelineHSet(hKey, conversionJson(analysisModuleMap));
        }
    }

    @Override
    public void refreshAssetExpression(BusinessParam param) {
        Assert.isTrue(StringUtil.isNotEmpty(param.getTableName()), "请传入tableName");
        List<TCalAsset> calAssets = getCalAssets(param);
        if (CollectionUtil.isEmpty(calAssets)) {
            return;
        }
        List<Long> ids = calAssets.stream().map(TCalAsset::getId).collect(Collectors.toList());
        List<TAssetExpressionVO> assetExpressions = assetExpressionService.queryListByAssetIds(ids, param.getTableName());
        if (CollectionUtil.isEmpty(assetExpressions)) {
            return;
        }
        Map<String, List<TAssetExpressionVO>> listMap = assetExpressions.stream().collect(Collectors.groupingBy(TAssetExpressionVO::getAssetNum));
        for (Map.Entry<String, List<TAssetExpressionVO>> stringListEntry : listMap.entrySet()) {
            String assetNum = stringListEntry.getKey();
            List<TAssetExpressionVO> value = stringListEntry.getValue();
            Map<String, TAssetExpressionVO> expressionMap = value.stream().collect(Collectors.toMap(TAssetExpressionVO::getCalLabel, Function.identity(), (a, b) -> a));
            String hKey = String.format(RedisKeyConstants.ASSET_EXPRESSION_PREFIX, param.getDeptNum(), assetNum);
            delOldHashKey(hKey, expressionMap.keySet());
            redisService.pipelineHSet(hKey, conversionJson(expressionMap));
        }
    }

    public void refreshStaticModule(BusinessParam param) {
        List<TCalAsset> calAssets = getCalAssets(param);
        if (CollectionUtil.isEmpty(calAssets)) {
            return;
        }
        Set<String> assetNums = calAssets.stream().map(TCalAsset::getAssetNum).collect(Collectors.toSet());

        Map<String, Map<String, IotValue>> redisCacheMap = assetNums.stream().collect(Collectors.toMap(Function.identity(), t -> Maps.newHashMap()));
        List<AssetStaticPropertiesInstanceVO> propertiesInstances = staticPropertiesInstanceService.listVOByAssetNums(assetNums);
        Map<String, List<AssetStaticPropertiesInstanceVO>> listMap = propertiesInstances.stream().collect(Collectors.groupingBy(AssetStaticPropertiesInstanceVO::getAssetNum));
        for (Map.Entry<String, List<AssetStaticPropertiesInstanceVO>> stringListEntry : listMap.entrySet()) {
            String assetNum = stringListEntry.getKey();
            List<AssetStaticPropertiesInstanceVO> value = stringListEntry.getValue();
            Map<String, IotValue> labelValueMap = value.stream().collect(Collectors.toMap(AssetStaticPropertiesInstanceVO::getLabel, IotValue::of, (a, b) -> b));
            redisCacheMap.get(assetNum).putAll(labelValueMap);
        }
        redisCacheMap.forEach((assetNum, labelValueMap) -> {
            String hKey = String.format(RedisKeyConstants.ASSET_STATIC_PREFIX, param.getDeptNum(), assetNum);
            delOldHashKey(hKey, labelValueMap.keySet());
            if (labelValueMap.isEmpty()) return;
            redisService.hmSet(hKey, conversionJson(labelValueMap));
        });
    }

    private void delStaticCache(String hKey, Set<String> newLabels) throws RedisConnectException {
        Map<String, String> stringStringMap = redisService.hGetAll(databaseByData, hKey);
        for (Map.Entry<String, String> entry : stringStringMap.entrySet()) {
            String label = entry.getKey();
            IotValue iotValue = JSON.parseObject(entry.getValue(), IotValue.class);
            if (Objects.equals(StringPools.STATIC_DATA, iotValue.getType()) && !newLabels.contains(iotValue.getLabel())) {
                try {
                    redisService.hdel(databaseByData, hKey, label);
                } catch (RedisConnectException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    @Override
    public void refreshVirtualAsset() {
        //每次刷都是整个系统刷.虚拟资产数量少
        List<TCalAsset> list = calAssetService.list(Wrappers.<TCalAsset>lambdaQuery().eq(TCalAsset::getVirtualFlag, true));
        list.removeIf(asset -> StringUtil.isEmpty(asset.getReferenceAssetNum()));
        if (list.isEmpty()) return;
        Set<Long> groupIds = list.stream().map(TCalAsset::getAssetGroupId).collect(Collectors.toSet());
        List<TAssetGroup> assetGroups = assetGroupService.getByIds(groupIds);
        Map<Long, String> groupNameMap = assetGroups.stream().collect(Collectors.toMap(TAssetGroup::getId, TAssetGroup::getName));
        Map<String, List<VirtualMappingBody>> virtualAssetMap = ListUtil.groupList(list, a -> String.format(RedisKeyConstants.ASSET_VIRTUAL, a.getReferenceAssetNum()), asset -> {
            String groupName = groupNameMap.get(asset.getAssetGroupId());
            if (StringUtil.isEmpty(groupName)) return null;
            return VirtualMappingBody.of(groupName, asset.getAssetNum());
        });
        virtualAssetMap.forEach((key, groupNames) -> {
            groupNames.removeIf(Objects::isNull);
            try {
                redisService.set(key, JSON.toJSONString(groupNames));
            } catch (RedisConnectException e) {
                throw new RuntimeException(e);
            }
        });
        //del old
        try {
            Set<String> keys = redisService.getKeys(RedisKeyConstants.ASSET_VIRTUAL_FRAGMENT + "*");
            keys.removeIf(virtualAssetMap::containsKey);
            for (String key : keys) {
                redisService.del(key);
            }
        } catch (RedisConnectException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 根据新的键删除缓存中多余的键
     *
     * @param hKey   键
     * @param newKey hKey内部的新key
     */
    private void delOldHashKey(String hKey, Set<String> newKey) {
        Map<String, String> oldMap = null;
        try {
            oldMap = redisService.hGetAll(hKey);
        } catch (RedisConnectException e) {
            throw new RuntimeException(e);
        }

        for (String key : oldMap.keySet()) {
            if (!newKey.contains(key)) {
                try {
                    redisService.hdel(hKey, key);
                } catch (RedisConnectException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    public void refreshEdgeCache(BusinessParam param) {
        List<TCalAsset> calAssets = getCalAssets(param);
        //只刷虚拟资产
        calAssets.removeIf(asset -> !asset.getVirtualFlag());
        List<String> assetNums = calAssets.stream().map(TCalAsset::getAssetNum).collect(Collectors.toList());
        List<AssetEdgeInputInstanceVO> assetEdgeInputInstanceVOS = assetEdgeInputInstanceService.listVOByAssetNums(new HashSet<>(assetNums));
        Map<String, List<AssetEdgeInputInstanceVO>> stringListMap = ListUtil.groupList(assetEdgeInputInstanceVOS, AssetEdgeInputInstanceVO::getAssetNum);
        ArrayList<String> list = Lists.newArrayList();
        stringListMap.forEach((s, assetEdgeInputInstanceVOS1) -> {
            Set<String> labels = assetEdgeInputInstanceVOS1.stream().map(AssetEdgeInputInstanceVO::getLabel).collect(Collectors.toSet());
            list.add(String.format(RedisKeyConstants.ASSET_EDGE_PREFIX, param.getDeptNum(), s));
            list.add(JSON.toJSONString(labels));
        });
        try {
            redisService.mSet(list.toArray(new String[0]));
        } catch (RedisConnectException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void refreshCacheByDeptNum(String deptNum) {
        try {
            LOCK_MAP.computeIfAbsent(deptNum, s -> new ReentrantLock()).lock();

            log.info("刷新缓存:{}", deptNum);
            long l = System.currentTimeMillis();
            BusinessParam param = BusinessParam.of(deptNum);
            this.refreshAssetGroup(param);
            this.refreshAssetAnalysis(param);
            this.refreshAssetInstanceData(param);
            this.refreshAssetInstanceTime(param);
            this.refreshStaticModule(param);
            this.refreshEdgeCache(param);
            this.refreshVirtualAsset();
            HashSet<String> instances = Sets.newHashSet("t_asset_indicators_instance");
            instances.forEach(tableName -> {
                //todo 里面的sql还没有做通用化,以后有新组件用到表达式和变量的话考虑做成通用sql
                BusinessParam businessParam = BusinessParam.of(deptNum, tableName);
                this.refreshAssetCallabel(businessParam);
                this.refreshAssetExpression(businessParam);
                this.refreshAssetLabel(businessParam);
            });
            log.info("{}缓存刷新完毕,耗时：{}s", deptNum, (System.currentTimeMillis() - l) / 1000.0);
            long l1 = System.currentTimeMillis();
            //删除无用的设备编号缓存
            List<TCalAsset> calAssets = calAssetService.queryAssetList(deptNum);
            HashMap<String, List<String>> map = new HashMap<>();
            calAssets.forEach(asset -> {
                String assetNum = asset.getAssetNum();
                List<String> keys = Lists.newArrayList(
                        String.format(RedisKeyConstants.ASSET_EXPRESSION_PREFIX, deptNum, assetNum),
                        String.format(RedisKeyConstants.ASSET_CALLABEL_PREFIX, deptNum, assetNum),
                        String.format(RedisKeyConstants.ASSET_USAGE_ANALYSIS_PREFIX, deptNum, assetNum),
                        String.format(RedisKeyConstants.ASSET_LABEL_PREFIX, deptNum, assetNum),
                        String.format(RedisKeyConstants.ASSET_INDICATORS_INSTANCE_TIME_PREFIX, deptNum, assetNum),
                        String.format(RedisKeyConstants.ASSET_INDICATORS_INSTANCE_DATA_PREFIX, deptNum, assetNum),
                        String.format(RedisKeyConstants.ASSET_EDGE_PREFIX, deptNum, assetNum)
                );
                map.put(assetNum, keys);
            });
            try {
                Set<String> keys = new HashSet<>();
                keys.addAll(redisService.getKeys(String.format(RedisKeyConstants.ASSET_CALLABEL_FRAGMENT, deptNum) + "*"));
                keys.addAll(redisService.getKeys(String.format(RedisKeyConstants.ASSET_EXPRESSION_FRAGMENT, deptNum) + "*"));
                keys.addAll(redisService.getKeys(String.format(RedisKeyConstants.ASSET_INDICATORS_INSTANCE_DATA_FRAGMENT, deptNum) + "*"));
                keys.addAll(redisService.getKeys(String.format(RedisKeyConstants.ASSET_INDICATORS_INSTANCE_TIME_FRAGMENT, deptNum) + "*"));
                keys.addAll(redisService.getKeys(String.format(RedisKeyConstants.ASSET_LABEL_FRAGMENT, deptNum) + "*"));
                keys.addAll(redisService.getKeys(String.format(RedisKeyConstants.ASSET_USAGE_ANALYSIS_FRAGMENT, deptNum) + "*"));
                keys.addAll(redisService.getKeys(String.format(RedisKeyConstants.ASSET_EDGE_FRAGMENT, deptNum) + "*"));
                List<String> myKeys = map.values().stream().flatMap(Collection::stream).collect(Collectors.toList());
                myKeys.forEach(keys::remove);
                for (String key : keys) {
                    redisService.del(key);
                }
                TAssetGroup byName = assetGroupService.getByName(deptNum);
                if (byName == null || !byName.getIsValid()) {
                    redisService.del(String.format(RedisKeyConstants.ASSET_CHILD_PREFIX, deptNum, deptNum));
                }
            } catch (RedisConnectException e) {
                throw new RuntimeException(e);
            }
            //通知计算程序刷新缓存
            informToCalculate(Lists.newArrayList(deptNum));
            log.info("{}无用缓存删除完毕,耗时：{}s", deptNum, (System.currentTimeMillis() - l1) / 1000.0);
        } finally {
            if (LOCK_MAP.containsKey(deptNum)) LOCK_MAP.get(deptNum).unlock();
        }
    }

    public void informToCalculate(List<String> deptNums) {
        redisMessagePublisher.publish(flushCacheChannelName, JSON.toJSONString(deptNums));
    }
}
